package de.sisy.RemoteFileManager;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Stack;
import java.util.TreeMap;
import java.util.Vector;

import se.sisy.Connection.SshConnection;

import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.ChannelSftp.LsEntry;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.SftpException;
import com.lamerman.FileDialog;

import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ListActivity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import android.widget.Toast;

public class RemoteFileBrowserActivity extends ListActivity {

	private static final String ITEM_KEY = "key";
	private static final String ITEM_IMAGE = "image";
	private static final String ROOT = "/";
    static final int REQUEST_SAVE = 0;


	public static final String START_PATH = "START_PATH";
	public static final String RESULT_PATH = "RESULT_PATH";
	public static final String SELECTION_MODE = "SELECTION_MODE";

	private List<String> path = null;
	List<String> item = new ArrayList<String>();
	private TextView myPath;
	private EditText mFileName;
	private ArrayList<HashMap<String, Object>> mList;

	private Button uploadButton;

	private LinearLayout layoutSelect;
	private LinearLayout layoutCreate;
	private InputMethodManager inputManager;
	private String parentPath = ROOT;
	private String currentPath = ROOT;

	private Stack<String> pathHistory;
	
	private int selectionMode = SelectionMode.MODE_CREATE;

	private HashMap<String, Integer> lastPositions = new HashMap<String, Integer>();
	private ChannelSftp sshChannel;
	private int numberOfFolders;
	private String downloadFolder = "/sdcard/Sam";
	private String fileToDownload;

	/** Wird aufgerufen wenn die Activity zum ersten mal gestartet wird */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		SshConnection connection = SshConnection.getInstance();
		pathHistory = new Stack<String>();
		//pathHistory.push(ROOT);
		
		sshChannel = connection.getChannel();
		
		setResult(RESULT_CANCELED, getIntent());

		setContentView(R.layout.file_dialog_remote);
		myPath = (TextView) findViewById(R.id.path);
		mFileName = (EditText) findViewById(R.id.fdEditTextFile);

		inputManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);

		uploadButton = (Button) findViewById(R.id.fdButtonSelect);
		uploadButton.setEnabled(true);
		uploadButton.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				try {
					
					Intent intent = new Intent(v.getContext(), FileDialog.class);
					intent.putExtra(FileDialog.START_PATH, "/sdcard");
					startActivityForResult(intent, REQUEST_SAVE);
					
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});

		final Button newButton = (Button) findViewById(R.id.fdButtonNew);
		newButton.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				setCreateVisible(v);

				mFileName.setText("");
				mFileName.requestFocus();
			}
		});

		selectionMode = getIntent().getIntExtra(SELECTION_MODE,
				SelectionMode.MODE_CREATE);
		if (selectionMode == SelectionMode.MODE_OPEN) {
			newButton.setEnabled(false);
		}

		layoutSelect = (LinearLayout) findViewById(R.id.fdLinearLayoutSelect);
		layoutCreate = (LinearLayout) findViewById(R.id.fdLinearLayoutCreate);
		layoutCreate.setVisibility(View.GONE);

		final Button cancelButton = (Button) findViewById(R.id.fdButtonCancel);
		cancelButton.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				setSelectVisible(v);
			}

		});
		final Button createButton = (Button) findViewById(R.id.fdButtonCreate);
		createButton.setOnClickListener(new OnClickListener() {

			@Override 
			public void onClick(View v) {
				if (mFileName.getText().length() > 0) {
					getIntent().putExtra(RESULT_PATH,
							currentPath + "/" + mFileName.getText());
					setResult(RESULT_OK, getIntent());
					finish();
				}
			}
		});

		String startPath = getIntent().getStringExtra(START_PATH);
		if (startPath != null) {
			getDir(startPath);
		} else {
			getDir(ROOT);
		}
		
		
		
	}

	
	/**
	 * Der Einstiegspunkt um in einen neuen Ordner zu wechseln, bereitet das laden des
	 * Ordners vor
	 * @param dirPath der Path in den gewechselt werden soll.
	 */
	private void getDir(String dirPath) {

		boolean useAutoSelection = dirPath.length() < currentPath.length();

		Integer position = lastPositions.get(parentPath);

		getDirImpl(dirPath);

		if (position != null && useAutoSelection) {
			getListView().setSelection(position);
		}

	}

	/**
	 * Hier wird ein neuer Ordner geladen und der Inhalt für die Anzeige vorbereietet
	 * @param dirPath
	 */
	private void getDirImpl(final String dirPath) {

		currentPath = dirPath;

		path = new ArrayList<String>();
		item = new ArrayList<String>();
		mList = new ArrayList<HashMap<String, Object>>();

		//SSH Stuff
		Vector result;
		ArrayList<LsEntry> files = new ArrayList<LsEntry>();
		try {
			result = sshChannel.ls(dirPath);
			if (result != null) {
				for (int ii = 0; ii < result.size(); ii++) {
					Object obj = result.elementAt(ii);
					if (obj instanceof LsEntry) {
						files.add((LsEntry)obj);
					}

				}
			}
		} catch (SftpException e) {
			e.printStackTrace();
		}
		
		
		myPath.setText(getText(R.string.location) + ": " + dirPath );

//		if (!currentPath.equals(ROOT)) {
//
//			item.add(ROOT);
//			addItem(ROOT, R.drawable.folder);
//			path.add(ROOT);
//
//			item.add("../");
//			addItem("../", R.drawable.folder);
//			path.add(parentPath);
//			//parentPath = f.getParent();
//
//		}

		numberOfFolders = 0;
		
		TreeMap<String, String> dirsMap = new TreeMap<String, String>();
		TreeMap<String, String> dirsPathMap = new TreeMap<String, String>();
		TreeMap<String, String> filesMap = new TreeMap<String, String>();
		TreeMap<String, String> filesPathMap = new TreeMap<String, String>();
		for (LsEntry file : files) {
			if (file.getAttrs().isDir()) {
				String dirName = file.getFilename();
				dirsMap.put(dirName, dirName);
				dirsPathMap.put(dirName, dirPath+file.getFilename()+"/");
			} else {
				filesMap.put(file.getFilename(), file.getFilename());
				filesPathMap.put(dirPath, dirPath);
			}
		}
		item.addAll(dirsMap.tailMap("").values());
		item.addAll(filesMap.tailMap("").values());
		path.addAll(dirsPathMap.tailMap("").values());
		path.addAll(filesPathMap.tailMap("").values());

		numberOfFolders = dirsMap.size();
		SimpleAdapter fileList = new SimpleAdapter(this, mList,
				R.layout.file_dialog_row,
				new String[] { ITEM_KEY, ITEM_IMAGE }, new int[] {
						R.id.fdrowtext, R.id.fdrowimage });

		for (String dir : dirsMap.tailMap("").values()) {
			addItem(dir, R.drawable.folder);
		}

		for (String file : filesMap.tailMap("").values()) {
			addItem(file, R.drawable.file);
		}

		fileList.notifyDataSetChanged();

		setListAdapter(fileList);

	}

	private void addItem(String fileName, int imageId) {
		HashMap<String, Object> item = new HashMap<String, Object>();
		item.put(ITEM_KEY, fileName);
		item.put(ITEM_IMAGE, imageId);
		mList.add(item);
	}

	/**
	 * Diese Methode wird von System aufgerufen wenn auf ein Listeneelement geklickt wird.
	 * Hier muss unterschieden werden ob es sich um "..", einen Ordner oder eine Datei handelt.
	 */
	@Override
	protected void onListItemClick(ListView l, View v, int position, long id) {


		setSelectVisible(v);

		if (position == 0) {
			pathHistory.clear();
			pathHistory.push(ROOT);
			getDir(ROOT);
			
		}
		
		//auf ".." geklickt, also in Vaterordner wechseln
		else if (position == 1) {
				getDir(pathHistory.pop());
		}
		
		//auf einen ordner geklickt
		else if (position < numberOfFolders) {
			
			String pathToGet = path.get(position);
			
			pathHistory.push(currentPath);
			parentPath = currentPath;
			currentPath = pathToGet;
			
			uploadButton.setEnabled(true);
				lastPositions.put(currentPath, position);
				getDir(pathToGet);
		// auf datei geklickt: datei downloaden
		} else {
			final String fileName = item.get(position);

			fileToDownload = fileName;
			showDialog(1);
		}
	}
	
	/**
	 * Diese Methode wird vom system aufgerufen wenn man der Activity sagt dass sie einen Dialog
	 * anzeigen soll. Mit der ID kann man verschiedene Dialoge anfordern
	 */
	@Override
	protected Dialog onCreateDialog(int id) {
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setMessage("Do you want do download this file?")
		       .setCancelable(false)
		       .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
		           public void onClick(DialogInterface dialog, int id) {
		        	   downloadFile(fileToDownload);
		           }
		       })
		       .setNegativeButton("No", new DialogInterface.OnClickListener() {
		           public void onClick(DialogInterface dialog, int id) {
		                dialog.cancel();
		           }
		       });
		AlertDialog alert = builder.create();
		return alert;
	}

	/**
	 * Lädt eine Datei auf das Telefon vom remote Server herunter. Das geschieht
	 * über eine scp verbindung und wird von der Jsch Lib gehandlet.
	 * @param fileName (nur) der Dateiname.
	 */
	protected void downloadFile(String fileName) {
//		SftpProgressMonitor monitor = new MyProgressMonitor();
		int mode = ChannelSftp.OVERWRITE;
		try {
			sshChannel.get(currentPath+fileName, downloadFolder, null, mode);
		} catch (SftpException e) {
			Context context = getApplicationContext();
			CharSequence text = "Error during dowoad, try again!";
			int duration = Toast.LENGTH_SHORT;
			
			Toast toast = Toast.makeText(context, text, duration);
			toast.show();
		}		
	}
	
	/**
	 * Hiermit wierd eine Datei in den aktuellen Ordner auf dem remote Server
	 * hochgeladen.
	 * @param fileNamePlusPath Der volle qualifizierende Dateimane mit Pfad
	 */
	protected void uploadFile(String fileNamePlusPath) {
//		SftpProgressMonitor monitor = new MyProgressMonitor();
		int mode = ChannelSftp.OVERWRITE;
		try {
			sshChannel.put(fileNamePlusPath, currentPath, null, mode);
		} catch (SftpException e) {
			Context context = getApplicationContext();
			CharSequence text = "Error during upload, try again!";
			int duration = Toast.LENGTH_SHORT;
			
			Toast toast = Toast.makeText(context, text, duration);
			toast.show();
		}		
	}

	/**
	 * Hier wird ein Tastendruck auf die Android-steuertasten abgefangen und behandelt (Zurück und Menü).
	 */
	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		if ((keyCode == KeyEvent.KEYCODE_BACK)) {
			uploadButton.setEnabled(true);

			if (layoutCreate.getVisibility() == View.VISIBLE) {
				layoutCreate.setVisibility(View.GONE);
				layoutSelect.setVisibility(View.VISIBLE);
			} else {
				if (!currentPath.equals(ROOT)) {
					getDir(parentPath);
				} else {
					return super.onKeyDown(keyCode, event);
				}
			}

			return true;
		} else {
			return super.onKeyDown(keyCode, event);
		}
	}

	/**
	 * schaltet das Orndernamen-Eingabefeld für die "neuer Ordner" Funktion sichtbar.
	 * die "neuer Ordner" Funktion ist noch nicht implementiert!
	 * @param v
	 */
	private void setCreateVisible(View v) {
		layoutCreate.setVisibility(View.VISIBLE);
		layoutSelect.setVisibility(View.GONE);

		inputManager.hideSoftInputFromWindow(v.getWindowToken(), 0);
	}

	private void setSelectVisible(View v) {
		layoutCreate.setVisibility(View.GONE);
		layoutSelect.setVisibility(View.VISIBLE);

		inputManager.hideSoftInputFromWindow(v.getWindowToken(), 0);
	}
	
	/**
	 * Diese Methode wird vom System aufgerufen wenn eine Andere Activity gestartet wurde
	 * mit der Aweisung ein Ergebnis zurück zu liefern, und diese und beendet wird.
	 */
	protected void onActivityResult(int requestCode, int resultCode,
            Intent data) {
    	// onActivityResult f�r den local Filemanager
        if (requestCode == REQUEST_SAVE) {
            if (resultCode == RESULT_OK) {
                // Dateipfad der ausgew�hlten Datei
                String pickedfilepath = data.getStringExtra(FileDialog.RESULT_PATH);
                System.out.println(pickedfilepath);
                
                uploadFile(pickedfilepath);
                
                Context context = getApplicationContext();
				CharSequence text = pickedfilepath;
				int duration = Toast.LENGTH_SHORT;

				Toast toast = Toast.makeText(context, text, duration);
				toast.show();
            }
        }
    }
}